package com.utf999.qiangmanger.controller.permission;

import java.io.PrintWriter;
import java.lang.reflect.Method;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import com.utf999.qiangmanger.entity.JsonEntity;
import com.utf999.qiangmanger.entity.orm.AdminUserEntity;
import com.utf999.qiangmanger.exception.AuthenticationException;
import com.utf999.qiangmanger.exception.BizException;
import com.utf999.qiangmanger.exception.ResponseCode;
import com.utf999.qiangmanger.service.iface.IAdminUserService;

import com.utf999.qiangmanger.utils.JSONUtils;

/**
 * 负责http协议权限验证的AOP切面。<br>
 * 这里我们配合动态注解NeedAuthority对HTTP层的token有效性进行验证<br>
 * 如果没有发现token或者token不合法，那么抛出异常，不在进行http接口的执行了
 * @author yinwenjie
 */
public class AuthorityMethodInterceptor extends HandlerInterceptorAdapter {
	
	@Autowired
	private IAdminUserService adminUserService;

	/* (non-Javadoc)
	 * @see org.springframework.web.servlet.handler.HandlerInterceptorAdapter#preHandle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object)
	 */
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
		//如果条件成立，说明拦截器无效
		if (handler == null || !(handler instanceof HandlerMethod)) {
			return true;
		}
		
		HandlerMethod handlerMethod = (HandlerMethod)handler;
		Method method = handlerMethod.getMethod();
		AuthorityAnnotation authorityAnnotation = method.getAnnotation(AuthorityAnnotation.class);
		
		//如果条件成立，说明不需要判断token的信息，因为没有权限要求。
		if(authorityAnnotation ==  null) {
			return true;
		}
		
		/*
		 * 一旦发现 方法有鉴权要求，这个方法 需要做以下的事情：
		 * 1、提取这个注解信息中的scope、prompt信息
		 * 2、从cookies信息中找到token信息，并取出这个token中的用户信息（没有token则返回）
		 * 3、查询这个token对应的用户信息
		 * 4、从用当前用户中的角色信息，和scope的权限范围进行对比，对比到符合的角色，就可以认为鉴权成功了。
		 * 
		 * 注意，一旦验证错误，需要根据prompt信息中不同的提示方式进行提示
		 * ajax方式的话进行ajax的提示
		 * redirect方式的话，抛出AuthenticationException异常，跳转到登录页面
		 * */
		//===================1
		AuthorityScope[] scopes = authorityAnnotation.scope();
		PromptModeType promptMode = authorityAnnotation.promptMode();
		
		//===================2
		Cookie[] cookies = request.getCookies();
		String token = null;
		for(int index = 0 ; cookies != null && index < cookies.length ; index++) {
			Cookie cookie = cookies[index];
			if(StringUtils.equals(cookie.getName(), "token")) {
				token = cookie.getValue();
			}
		}
		//如果条件成立，说明 没有token，那么进行报错处理
		if(StringUtils.isEmpty(token)) {
			//AJAX方式进行提示，否则就是抛出异常进行提示
			if(promptMode == PromptModeType.AJAX) {
				JsonEntity jsonEntity = new JsonEntity();
				jsonEntity.setErrorinfo("您的token信息缺失，这个接口需要操作者登录系统后才能操作。");
				jsonEntity.setResponsecode(ResponseCode.E402);
				
				//输出，输出后终止本次请求
				response.setCharacterEncoding("utf-8");
				response.setContentType("text/html; charset=UTF-8");
				PrintWriter out = null;
				try {
					out = response.getWriter();
				} catch (Exception e) {
					throw new BizException(e.getMessage(), ResponseCode.E501);
				}
				
				String jsonstr = JSONUtils.toString(jsonEntity); 
				out.print(jsonstr);
				return false;
			} else {
				throw new AuthenticationException(); 
			}
		}
		
		//===================3
		AdminUserEntity userInfo = null;
		try {
			userInfo = this.adminUserService.queryAdmingByToken(token);
		} catch(BizException e) {
			throw new AuthenticationException(); 
		}
				
		//如果没有发现用户信息，则报错
		if(userInfo == null) {
			//AJAX方式进行提示，否则就是抛出异常进行提示
			if(promptMode == PromptModeType.AJAX) {
				JsonEntity jsonEntity = new JsonEntity();
				jsonEntity = new JsonEntity();
				jsonEntity.setErrorinfo("您的token信息缺失，这个接口需要操作者登录系统后才能操作。");
				jsonEntity.setResponsecode(ResponseCode.E402);
				
				//输出，输出后终止本次请求
				response.setCharacterEncoding("utf-8");
				response.setContentType("text/html; charset=UTF-8");
				PrintWriter out = null;
				try {
					out = response.getWriter();
				} catch (Exception e) {
					throw new BizException(e.getMessage(), ResponseCode.E501);
				}
				
				String jsonstr = JSONUtils.toString(jsonEntity); 
				out.print(jsonstr);
				return false;
			} else {
				throw new AuthenticationException(); 
			}
		}
		
		//===================4
		Integer level = userInfo.getAdminLevel();
		for (AuthorityScope scope : scopes) {
			//鉴权成功，当前管理员的信息将存储到request中
			if(level == scope.getCode()) {
				request.setAttribute("admin",userInfo);
				return true;
			}
		}
		//如果循环内没有找到对应鉴权范围，那么说明鉴权失败
		//AJAX方式进行提示，否则就是抛出异常进行提示
		if(promptMode == PromptModeType.AJAX) {
			JsonEntity jsonEntity = new JsonEntity();
			jsonEntity = new JsonEntity();
			jsonEntity.setErrorinfo("您的token信息缺失，这个接口需要操作者登录系统后才能操作。");
			jsonEntity.setResponsecode(ResponseCode.E402);
			
			//输出，输出后终止本次请求
			response.setCharacterEncoding("utf-8");
			response.setContentType("text/html; charset=UTF-8");
			PrintWriter out = null;
			try {
				out = response.getWriter();
			} catch (Exception e) {
				throw new BizException(e.getMessage(), ResponseCode.E501);
			}
			
			String jsonstr = JSONUtils.toString(jsonEntity); 
			out.print(jsonstr);
			return false;
		} else {
			throw new AuthenticationException(); 
		}
	}
}
